package com.guoyh.bilbase.base.fragment

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import com.guoyh.baseutils.entity.LoadStatusEntity
import com.guoyh.baseutils.entity.LoadingDialogEntity
import com.guoyh.baseutils.entity.LoadingType
import com.guoyh.baseutils.ext.toast
import com.guoyh.baseutils.mylog.Loger
import com.guoyh.baseutils.viewModel.SupportViewModel
import com.guoyh.bilbase.base.BaseIView
import com.guoyh.bilbase.enums.PageStateEnum
import com.guoyh.bilbase.ext.*
import com.zy.multistatepage.MultiStateContainer

/**
 * 作者　: hegaojian
 * 时间　: 2020/11/18
 * 描述　:
 */
abstract class BaseDVFragment<DB : ViewDataBinding, VM : SupportViewModel> : BaseInitFragment(), BaseIView {


    //界面状态管理
    protected lateinit var mState: MultiStateContainer


    //当前页面的状态
    var pagetState: PageStateEnum = PageStateEnum.SUCCESS


    //是否第一次加载
    private var isFirst: Boolean = true


    lateinit var mDataBind: DB
    //当前Fragment绑定的泛型类ViewModel
    lateinit var mViewModel: VM


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val contentView = LayoutInflater.from(mActivity).inflate(layoutId, null)
        mDataBind = DataBindingUtil.bind<DB>(contentView)!!
        dataBindView = mDataBind.root

        isFirst = true
        Loger.dd(javaClass.simpleName)

        return if (getLoadingView() == null) {
            mState = dataBindView!!.initStatPage {
                onLoadRetry()
            }
            container?.removeView(mState)
            mState
        } else {
            dataBindView
        }

    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        mActivity = context as AppCompatActivity
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //生成ViewModel
        if (!this::mViewModel.isInitialized) {
            mViewModel = createViewModel()
        }

        initStatusView(view, savedInstanceState)
        initLoadingUiChange()
        initObserver()
        initData()
        onBindViewClick()
    }

    private fun initStatusView(view: View, savedInstanceState: Bundle?) {
        getLoadingView()?.let {
            //如果传入了自定义包裹view 将该view注册 做 空 错误 loading 布局处理
            mState = it.initStatPage {
                onLoadRetry()
            }
        }
        //view加载完成后执行
        view.post {
            initView(savedInstanceState)
        }
    }

    /**
     * 创建viewModel
     */
    private fun createViewModel(): VM {
        return ViewModelProvider(this).get(viewModelClass())
    }

    abstract fun viewModelClass(): Class<VM>

    
    
    /**
     * 初始化view操作
     */
    abstract fun initView(savedInstanceState: Bundle?)
    /**
     * 创建观察者
     */
    open fun initObserver() {}
    /**
     * 获取数据
     */
    open fun initData() {}


    /**
     * 懒加载
     */
    open fun lazyLoadData() {}



    override fun onResume() {
        super.onResume()
        onVisible()
    }

    /**
     * 是否需要懒加载
     */
    private fun onVisible() {
        if (lifecycle.currentState == Lifecycle.State.STARTED && isFirst) {
            view?.post {
                lazyLoadData()
                isFirst = false
            }
        }
    }

    /**
     * 子类可传入需要被包裹的View，做状态显示-空、错误、加载
     * 如果子类不覆盖该方法 那么会将整个当前Fragment界面都当做View包裹
     */
    override fun getLoadingView(): View? {
        return null
    }

    /**
     * 点击事件方法 配合setOnclick()拓展函数调用，做到黄油刀类似的点击事件
     */
    open fun onBindViewClick() {}

    /**
     * 注册 UI 事件 监听请求时的回调UI的操作
     */
    private fun initLoadingUiChange() {
        mViewModel.loadingChange.run {

            loading.observeInFragment(this@BaseDVFragment) {
                when (it.loadingType) {
                    //通用弹窗Dialog
                    LoadingType.LOADING_DIALOG -> {
                        if (it.isShow) {
                            showLoading(it)
                        } else {
                            dismissLoading(it)
                        }
                    }
                    //不同的请求自定义loading
                    LoadingType.LOADING_CUSTOM -> {
                        if (it.isShow) {
                            showCustomLoading(it)
                        } else {
                            dismissCustomLoading(it)
                        }
                    }
                    //请求时 xml显示 loading
                    LoadingType.LOADING_XML -> {
                        if (it.isShow) {
                            showLoadingUi()
                        }
                    }
                }
            }
            //当分页列表数据第一页返回空数据时 显示空布局
            showEmpty.observeInFragment(this@BaseDVFragment) {
                onRequestEmpty(it)
            }
            //当请求失败时
            showError.observeInFragment(this@BaseDVFragment) {
                if (it.loadingType == LoadingType.LOADING_XML) {
                    showErrorUi(it.errorMessage)
                }
                onRequestError(it)
            }
            //如果是 LoadingType.LOADING_XML，当请求成功时 会显示正常的成功布局
            showSuccess.observeInFragment(this@BaseDVFragment) {
                showSuccessUi()
            }
        }
    }

    /**
     * 请求列表数据为空时 回调
     * @param loadStatus LoadStatusEntity
     */
    override fun onRequestEmpty(loadStatus: LoadStatusEntity) {
        Loger.dd("aaaaa",loadStatus)
        showEmptyUi()
    }

    /**
     * 请求接口失败回调，如果界面有请求接口，需要处理错误业务，请实现它 如果不实现那么 默认吐司错误消息
     * @param loadStatus LoadStatusEntity
     */
    override fun onRequestError(loadStatus: LoadStatusEntity) {
        loadStatus.errorMessage.toast()
    }

    /**
     * 空界面，错误界面 点击重试时触发的方法，如果有使用 状态布局的话，一般子类都要实现
     */
    override fun onLoadRetry() {
        initData()
    }


    /**
     * 显示 成功状态界面
     */
    override fun showSuccessUi() {
        if (this::mState.isInitialized && pagetState != PageStateEnum.SUCCESS) {
            pagetState = PageStateEnum.SUCCESS
            mState.showSuccess()
        }
    }

    /**
     * 显示 错误 状态界面
     * @param errMessage String
     */
    override fun showErrorUi(msg: String, @DrawableRes drawableRes: Int) {
        if (this::mState.isInitialized && pagetState != PageStateEnum.ERROR) {
            pagetState = PageStateEnum.ERROR
            mState.showError(msg, drawableRes)
        }

    }

    /**
     * 显示 错误 状态界面
     */
    override fun showEmptyUi(msg: String, @DrawableRes drawableRes: Int) {
        Loger.dd(this::mState.isInitialized && pagetState != PageStateEnum.EMPTY)
        if (this::mState.isInitialized && pagetState != PageStateEnum.EMPTY) {
            pagetState = PageStateEnum.EMPTY
            mState.showEmpty(msg, drawableRes)
        }
    }

    fun showEmptyBtn(msg: String, @DrawableRes drawableRes: Int,btns:String,btnClick:()->Unit){
        mState.showEmptyAnBtn(msg,drawableRes,btns,btnClick)
    }
    /**
     * 显示 loading 状态界面
     */

    override fun showLoadingUi(msg: String) {
        if (this::mState.isInitialized && pagetState != PageStateEnum.LOADING) {
            pagetState = PageStateEnum.LOADING
            mState.showLoading(msg)
        }
    }

    /**
     * 显示自定义loading 在请求时 设置 loadingType类型为LOADING_CUSTOM 时才有效 可以根据setting中的requestCode判断
     * 具体是哪个请求显示该请求自定义的loading
     * @param setting LoadingDialogEntity
     */
    override fun showCustomLoading(setting: LoadingDialogEntity) {
        showLoadingExt(setting.loadingMessage)
    }

    /**
     * 隐藏自定义loading 在请求时 设置 loadingType类型为LOADING_CUSTOM 时才有效 可以根据setting中的requestCode判断
     * 具体是哪个请求隐藏该请求自定义的loading
     * @param setting LoadingDialogEntity
     */
    override fun dismissCustomLoading(setting: LoadingDialogEntity) {
        dismissLoadingExt()
    }

    override fun showLoading(setting: LoadingDialogEntity) {
        showLoadingExt()
    }

    override fun dismissLoading(setting: LoadingDialogEntity) {
        dismissLoadingExt()
    }

}